'''
模型类：主要与数据库交互，类--表  字段--字段  进行迁移可以修改字段
       也可以在类中定义方法给序列化器调用序列化
'''

# 用户抽象模型类允许我们继承，扩展字段来使用Django认证系统的用户模型类
from django.contrib.auth.models import AbstractUser
from django.db import models # 关联数据库的模型类
from haoke_mall.utils.models import BaseModel # 公用的数据库字段（放到抽象模型类中）
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer, BadData
from django.conf import settings
# 先导包：AbstractUser，需要继承它

# Create your models here.
# 用户模型类（关联用户信息表，主表）



class User(AbstractUser):
    """
    用户模型类
    """
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    email_active = models.BooleanField(default=False, verbose_name='邮箱验证状态')
    default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True,
                                        on_delete=models.SET_NULL, verbose_name='默认地址')
    # 关联数据库表，用于迁移生成表
    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    # 实例化这个类就会返回一个结果：
    def __str__(self):
        return self.username

    # 生成验证邮箱链接的方法(在序列化器调用)
    def generate_email_verify_url(self):
        """
        生成邮箱激活链接：
        1，构造加密序列化器
        2，调用序列化dumps方法进行加密
        3，返回加密链接
        """
        # 1.创建加密序列化器 TimedJSONWebSignatureSerializer加密，需要pip安装itsdangerous模块
        serializer = TJWSSerializer(settings.SECRET_KEY, 3600 * 24)

        # 2.调用dumps方法进行加密, bytes
        data = {'user_id': self.id, 'email': self.email}
        token = serializer.dumps(data).decode()

        # 3.返回拼接后的激活url   这里的url是用户点击了之后跳转到项目之后来
        return 'http://127.0.0.1:8080/success_verify_email.html?token=' + token

    # 验证token的方法
    # @staticmethod（静态方法的注解，不能访问类的属性或方法）方法可以不加self参数
    def check_verify_email_token(self,token):
        """
        对token进行解密并查询对应的uer
        :param token:
        :return:
        """
        serializer = TJWSSerializer(settings.SECRET_KEY, 3600 * 24)
        # 调用loads解密
        try:
            data = serializer.loads(token)
        except BadData:
            return None

        else:
            id = data.get('user_id')
            email = data.get('email')
            # 验证是否存在
            try:
                user = User.objects.get(id=id, email=email)
            except User.DoesNotExist:
                return None
            else:
                return user

# 区域模型类（关联创建省市区数据表）
class Area(models.Model):
    """
    行政区划
    """
    name = models.CharField(max_length=20, verbose_name='名称')
    # 采用self自关联方式:需要使用`related_name`指明下级
    # 字段参数on_delete用于定义当删除关联对象时，外键字段的行为：models.SET_NULL表示将外键字段设置为NULL
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subs', null=True, blank=True, verbose_name='上级行政区划')

    class Meta:
        db_table = 'tb_areas'
        verbose_name = '行政区划'
        verbose_name_plural = '行政区划'

    def __str__(self):
        return self.name




# 保存用户地址的模型类（继承抽象模型类）
class Address(BaseModel):
    """
    用户地址
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
    title = models.CharField(max_length=20, verbose_name='地址名称')
    receiver = models.CharField(max_length=20, verbose_name='收货人')
    province = models.ForeignKey('Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省')
    city = models.ForeignKey('Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
    district = models.ForeignKey('Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
    place = models.CharField(max_length=50, verbose_name='地址')
    mobile = models.CharField(max_length=11, verbose_name='手机')
    tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
    email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
    is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'tb_address'
        verbose_name = '用户地址'
        verbose_name_plural = verbose_name
        ordering = ['-update_time']